/*
 * @Author: guoliuyong
 * @Date: 2021-10-26 19:30:50
 * @LastEditTime: 2021-10-27 14:35:05
 * @LastEditors: Please set LastEditors
 * @Description: 自封装promise
 * @FilePath: \implement-promise-manually\src\promise.js
 */

class MyPromise {
    constructor(excutor) {
        this.promiseStatus = "pedding";
        this.promiseResult = null;
        this.callBacks = [];
        try {
            excutor(this.resolve.bind(this), this.reject.bind(this));
        } catch (error) {
            this.reject(error);
        }
    }
    /**
     * @description: 回到成功调用函数,只有pending状态可以改变，执行异步任务时，
     * 手动在同步任务下执行callback
     * @param {*} data值
     * @return {*}
     */
    resolve(data) {
        if (this.promiseStatus !== "pedding") return;
        this.promiseStatus = "filfulled";
        this.promiseResult = data;
        this.callBacks.forEach(d => {
            d.onResolve(data);
        })
    }
    /**
     * @description: 回到失败调用函数
     * @param {*} data值
     * @return {*}
     */
    reject(data) {
        if (this.promiseStatus !== "pedding") return;
        this.promiseStatus = "rejected";
        this.promiseResult = data;
        this.callBacks.forEach(d => {
            d.onRejceted(data);
        })
    }
    /**
     * @description: then函数,将最终结果返回
     * @param {*} onResolve, onRejceted
     * @return {*}
     */
    then(onResolve, onRejceted) {
        if (typeof onResolve !== 'function') {
            /* 
                 如果onResolved未指定或不是一个函数
                 手动将其变成一个函数
                 这个函数要使得当前then()返回的Promise成功, 并能够将结果传入下一个then()的onResolved中
            */
                 onResolve = value => value
        }

        if (!onRejceted || typeof onRejceted !== 'function') {
            /* 
                 如果onRejected未指定或不是一个函数
                 手动将其变成一个函数
                 这个函数要使得当前then()返回的Promise失败, 并能够将结果传入下一个then()的onRejected中
            */
                 onRejceted = reason => {
                throw reason
            }
        }
        return new MyPromise((resolve, reject) => {

            if (this.promiseStatus === "filfulled") {
                try {
                    const returnValueon = onResolve(this.promiseResult);
                    if (returnValueon instanceof MyPromise) {
                        returnValueon.then(resolve, reject);
                    } else {
                        resolve(returnValueon || this.promiseResult);
                    }
                } catch (error) {
                    reject(error);
                }
            }
            if (this.promiseStatus === "rejected") {
                try {
                    const errorInfo = onRejceted(this.promiseResult);
                    if (errorInfo instanceof MyPromise) {
                        errorInfo.then(resolve, reject);
                    } else {
                        reject(errorInfo);
                    }
                } catch (error) {
                    reject(error);
                }
            }
            if (this.promiseStatus === "pedding") {
                this.callBacks.push({
                    onResolve: function (value) {
                        try { // 应对回调函数抛出错误的情况
                            let return_value = onResolved(value) // 把改变状态后Promise实例的值传给回调函数, 供其使用
                            if (return_value instanceof Promise) { // 应对返回的是一个Promise
                                return_value.then(resolve, reject)
                            } else { // 应对返回的是普通类型的值的情况
                                resolve(return_value)
                            }
                        } catch (return_value) {
                            reject(return_value)
                        }
                    },
                    onRejceted: function (value) {
                        try { // 应对回调函数抛出错误的情况
                            let return_value = onResolved(value) // 把改变状态后Promise实例的值传给回调函数, 供其使用
                            if (return_value instanceof Promise) { // 应对返回的是一个Promise
                                return_value.then(resolve, reject)
                            } else { // 应对返回的是普通类型的值的情况
                                resolve(return_value)
                            }
                        } catch (return_value) {
                            reject(return_value)
                        }
                    },
                })
            }
        })
    }
    catch (onRejceted) {
        return this.then(undefined, onRejceted);
    }
}